using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

using XRGLib;
using Console = XRGLib.Console;

namespace Examples
{
    public class Examples : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        Console console;

        int currentExample = 0;
        List<ExampleBase> examples = new List<ExampleBase>();

        const int ConWidth = 100;
        const int ConHeight = 75;

        Rectangle ExampleRect = new Rectangle(35, 1, 60, 60);

        int frameRate = 0;
        int frameCounter = 0;
        TimeSpan elapsedTime = TimeSpan.Zero;

        Font[] fonts = new Font[2];
        int currentFont = 0;

        public Examples()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";

            this.IsFixedTimeStep = true;
            graphics.SynchronizeWithVerticalRetrace = true;
        }

        protected override void Initialize()
        {
            base.Initialize();

            InputSystem.Initialize(Window);
            InputSystem.KeyDown += new EventHandler<KeyEventArgs>(EventInput_KeyDown);
            InputSystem.MouseDown += new EventHandler<MouseEventArgs>(InputSystem_MouseDown);
        }




        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);

            Texture2D FontTexture = Content.Load<Texture2D>("dejavu12x12_gs_tc");
            fonts[0] = Font.CreateFromTexture(FontTexture,FontLayout.TCOD,FontType.GreyscaleAA);

            FontTexture = Content.Load<Texture2D>("celtic_garamond_10x10_gs_tc");
            fonts[1] = Font.CreateFromTexture(FontTexture, FontLayout.TCOD, FontType.GreyscaleAA);

            console = new Console(GraphicsDevice, fonts[0], ConWidth, ConHeight);

            graphics.PreferredBackBufferWidth = ConWidth * fonts[0].CharacterWidth;
            graphics.PreferredBackBufferHeight = ConHeight * fonts[0].CharacterHeight;
            graphics.ApplyChanges();

            console.Root.Clear();

            examples.Add(new Example1(console, ExampleRect.Width, ExampleRect.Height, this));
            examples.Add(new Example2(console, ExampleRect.Width, ExampleRect.Height, this));
            examples.Add(new Example3(console, ExampleRect.Width, ExampleRect.Height, this));
            examples.Add(new Example4(console, ExampleRect.Width, ExampleRect.Height, this));
            examples.Add(new Example5(console, ExampleRect.Width, ExampleRect.Height, this));
        }


        protected override void UnloadContent()
        {
        }


        protected override void Update(GameTime gameTime)
        {
            elapsedTime += gameTime.ElapsedGameTime;

            if (elapsedTime > TimeSpan.FromSeconds(1))
            {
                elapsedTime -= TimeSpan.FromSeconds(1);
                frameRate = frameCounter;
                frameCounter = 0;
            }

            examples[currentExample].Update(gameTime);

            base.Update(gameTime);
        }


        protected override void Draw(GameTime gameTime)
        {
            frameCounter++;

            console.Root.Clear();

            DrawMenu();
            DrawStatus();

            console.Blit(examples[currentExample].ReDraw(), console.Root,
                ExampleRect.X, ExampleRect.Y);
            RenderTarget2D render = console.Flush();

            spriteBatch.Begin();
            {
                spriteBatch.Draw(render, Vector2.Zero, Color.White);
            }
            spriteBatch.End();

            base.Draw(gameTime);
        }


        void DrawMenu()
        {
            for (int i = 0; i < examples.Count; i++)
            {
                string str = string.Format("{0}: {1}", i, examples[i].Description);
                if (i == currentExample)
                {
                    console.Root.PrintString(0, i, str, Color.Black,Color.White);
                }
                else
                {
                    console.Root.PrintString(0, i, str);
                }
            }
        }

        void DrawStatus()
        {
            Rectangle statusRect = new Rectangle(0, console.Root.Height - 2, console.Root.Width, 1);

            string status = string.Format("FPS: {0} {1}",
                frameRate,IsFixedTimeStep?"(Fixed Time Step)":"(Unfixed Time Step");

            console.Root.PrintStringRect(statusRect, status, HorizontalAligment.Center, VerticalAlignment.Top);
            statusRect.Offset(0, 1);

            console.Root.PrintStringRect(statusRect, "[F] to change font, [T] to toggle time step fixed/unfixed", HorizontalAligment.Center,
                VerticalAlignment.Top);
        }

        void InputSystem_MouseDown(object sender, MouseEventArgs e)
        {
            int cx = e.X / console.CharacterWidth;
            int cy = e.Y / console.CharacterHeight;

            if (ExampleRect.Contains(cx, cy))
            {
                cx = cx - ExampleRect.Left;
                cy = cy - ExampleRect.Top;

                examples[currentExample].OnMouseButton(e.Button, cx, cy);
            }

        }

        void EventInput_KeyDown(object sender, KeyEventArgs e)
        {
            switch (e.KeyCode)
            {
                case Keys.T:
                    ToggleTimeStep();
                    break;

                case Keys.F:
                    ToggleFont();
                    break;

                case Keys.Down:
                    examples[currentExample].OnDeactivated();

                    currentExample++;
                    if (currentExample >= examples.Count)
                        currentExample = 0;

                    examples[currentExample].OnActivated();
                    break;

                case Keys.Up:
                    examples[currentExample].OnDeactivated();

                    currentExample--;
                    if (currentExample < 0)
                        currentExample = examples.Count - 1;

                    examples[currentExample].OnActivated();
                    break;

                case Keys.Escape:
                    Exit();
                    break;
            }

            examples[currentExample].OnKeyboard(e);
        }

        void ToggleTimeStep()
        {
            if (IsFixedTimeStep)
            {
                IsFixedTimeStep = false;
                graphics.SynchronizeWithVerticalRetrace = false;
                graphics.ApplyChanges();
            }
            else
            {
                IsFixedTimeStep = true;
                graphics.SynchronizeWithVerticalRetrace = true;
                graphics.ApplyChanges();
            }
        }

        void ToggleFont()
        {
            currentFont++;

            if (currentFont >= fonts.Length)
                currentFont = 0;

            console.ChangeFont(fonts[currentFont]);

            graphics.PreferredBackBufferWidth = ConWidth * fonts[currentFont].CharacterWidth;
            graphics.PreferredBackBufferHeight = ConHeight * fonts[currentFont].CharacterHeight;
            graphics.ApplyChanges();
        }

    }
}
